﻿using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using ServiceStack.DesignPatterns.Model;
using ServiceStack.Redis;

namespace Redis.Core
{
    /// <summary>
    /// Redis Set对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class RedisSet<T> : RedisBase
    {
        public RedisSet(Manager manager, String SetName)
            : base(manager.GetClient())
        {
            Name = SetName;
        }

        public RedisSet(String SetName)
            : base(Manager.Default.GetClient())
        {
            Name = SetName;
        }


        public T RandomItem()
        {
            String Value = Redis.GetRandomItemFromSet(Name);
            return JsonConvert.DeserializeObject<T>(Value);
        }

        public IList<T> Union(params String [] SetNames)
        {
            List<T> Result = new List<T>();
            if (!SetNames.Contains(Name))
            {
                SetNames = SetNames.Concat(new String[] { Name }).ToArray();
            }
            HashSet<String> Values = Redis.GetUnionFromSets(SetNames);
            if (Values == null || Values.Count == 0)
                return Result;
            foreach (var item in Values)
            {
                Result.Add(JsonConvert.DeserializeObject<T>(item));
            }
            return Result;
        }

        public Int64 StoreUnion(String IntoSortedSet, params String[] Sorteds)
        {
            if (!Sorteds.Contains(Name))
            {
                Sorteds = Sorteds.Concat(new String[] { Name }).ToArray();
            }
            return Redis.StoreUnionFromSortedSets(IntoSortedSet, Sorteds);
        }

        public IList<T> Intersect(params String[] SetNames)
        {
            List<T> Result = new List<T>();
            if (!SetNames.Contains(Name))
            {
                SetNames = SetNames.Concat(new String[] { Name }).ToArray();
            }
            HashSet<String> Values = Redis.GetIntersectFromSets(SetNames);
            if (Values == null || Values.Count == 0)
                return Result;
            foreach (var item in Values)
            {
                Result.Add(JsonConvert.DeserializeObject<T>(item));
            }
            return Result;
        }

        public IList<T> Differences(params String[] SetNames)
        {
            List<T> Result = new List<T>();
            if (!SetNames.Contains(Name))
            {
                SetNames = SetNames.Concat(new String[] { Name }).ToArray();
            }
            HashSet<String> Values = Redis.GetDifferencesFromSet(Name, SetNames);
            if (Values == null || Values.Count == 0)
                return Result;
            foreach (var item in Values)
            {
                Result.Add(JsonConvert.DeserializeObject<T>(item));
            }
            return Result;
        }

        public void StoreIntersect(String intoSetName, params String[] Sorteds)
        {
            if (!Sorteds.Contains(Name))
            {
                Sorteds = Sorteds.Concat(new String[] { Name }).ToArray();
            }
            Redis.StoreIntersectFromSets(intoSetName, Sorteds);
        }

        public void StoreDifferences(String intoSetName, params String[] Sorteds)
        {
            Redis.StoreDifferencesFromSet(intoSetName, Name, Sorteds);
        }





        public void MoveTo(String  ToSetName,T Item)
        {
            String Value = JsonConvert.SerializeObject(Item,Formatting.None, timeConverter);
            Redis.MoveBetweenSets(Name, ToSetName, Value);
        }





        public IList<T> Items()
        {
            List<T> Result = new List<T>();
            HashSet<String> Values = Redis.GetAllItemsFromSet(Name);
            if (Values == null || Values.Count == 0)
                return Result;
            foreach (var item in Values)
            {
                Result.Add(JsonConvert.DeserializeObject<T>(item));
            }
            return Result;
        }
        
        public void SetContains(T Item)
        {
            String Value = JsonConvert.SerializeObject(Item, Formatting.None, timeConverter);
            Redis.SetContainsItem(Name, Value);
        }
        public void Add(T Item)
        {
            String Value = JsonConvert.SerializeObject(Item, Formatting.None, timeConverter);
            Redis.AddItemToSet(Name, Value);
        }

        public void AddRange(IEnumerable<T> collection)
        {
            List<String> datas = new List<String>();
            foreach (var item in collection)
            {
                datas.Add(JsonConvert.SerializeObject(item, Formatting.None, timeConverter));
            }
            Redis.AddRangeToSet(Name, datas);
        }

        public void Remove(T Item)
        {
            String Value = JsonConvert.SerializeObject(Item, Formatting.None, timeConverter);
            Redis.RemoveItemFromSet(Name, Value);
        }

        public T Pop()
        {
            String Value = Redis.PopItemFromSet(Name);
            return JsonConvert.DeserializeObject<T>(Value);
        }




        public Boolean ExpireAt(DateTime expireAt)
        {
            return Redis.ExpireEntryAt(Name, expireAt);
        }


        public Boolean ExpireAt(TimeSpan expireIn)
        {
            return Redis.ExpireEntryIn(Name, expireIn);
        }

        public Boolean ExpireAt(Int32 expireIn)
        {
            return Redis.ExpireEntryIn(Name, new TimeSpan(0, 0, 0, 0, expireIn));
        }


        public void Rename(String newName)
        {
            Redis.RenameKey(Name,newName);
            Name = newName;
        }



        public void Clear()
        {
            Redis.RemoveAllFromList(Name);
        }



        public Int64 Count
        {
            get
            {
                return Redis.GetSetCount(Name);
            }
        }

        public TimeSpan GetTimeToLive()
        {
            return Redis.GetTimeToLive(Name);
        }


        public Boolean IsExist
        {
            get
            {
                return Redis.ContainsKey(Name);
            }
        }



        public void Delete()
        {
            Redis.Remove(Name);
        }



        public String Name { get; set; }

        private static Newtonsoft.Json.Converters.IsoDateTimeConverter timeConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter()
        {
            DateTimeFormat = "yyyy-MM-dd HH:mm:ss ffff"
        };
    }
}
